package playchess;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

public class PlayChessServlet 
		extends HttpServlet
{
	private static final long serialVersionUID = -1635809824880795310L;
	
	//string constants
	public static final String REQUEST_PARAM_NAME 	 = "name";
	public static final String REQUEST_PARAM_MESSAGE = "message";
	
	public static final String ENTITY_PROPERTY_NAME	 		 = "name";
	public static final String ENTITY_PROPERTY_MESSAGE 		 = "message";
	public static final String ENTITY_PROPERTY_CREATION_TIME = "creationTime";
	
	//long constants
	private static final long LIFETIME_PLAYERNAME	 = 60; //seconds
	private static final long LIFETIME_PLAYERMESSAGE = 60; //seconds
	private static final long REFRESH_TIME_MESSAGES	 = 20000; //milliseconds
	
	//google app engine datastore related
	private static final Key messagesKey 			= KeyFactory.createKey("messages", "messagesRoot");
	private static final Key playerNamesKey 		= KeyFactory.createKey("players", "playersRoot"); 
	private static final DatastoreWithTransaction datastore = new DatastoreWithTransaction();
	
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException
	{
		String currentPlayerName = escapeHTML(req.getParameter(REQUEST_PARAM_NAME) );
		String currentPlayerMessage = escapeHTML(req.getParameter(REQUEST_PARAM_MESSAGE) );
		PrintWriter respWriter = resp.getWriter();
		
		resp.setContentType("text/html");
		respWriter.println("<html><head>");
		
		if (currentPlayerName != null)
		{		
			respWriter.println(
					"<script>"
					+"pageUrl=\"http://3dividedby3.appspot.com/playchess\";"
					//+"pageUrl=\"http://localhost:8888/playchess\";"
					+"function sendMessage(_idMessage) {"
					+"var message=document.getElementById(_idMessage).value;"
					+"window.open(pageUrl+\"?name=" + currentPlayerName + "&message=\"+message, \"_self\");"
					+"} "
					+"function refresh() {"
					+"window.open(pageUrl+\"?name=" + currentPlayerName + "\", \"_self\");"
					+"} "
					+"</script>"
			);

			respWriter.println("</head><body onload=\"setTimeout('refresh()', " + REFRESH_TIME_MESSAGES + ");\">Players:<br />");
		
			deleteExpiredNames();
			if (!playerNameExists(currentPlayerName) )
			{
				addPlayerName(currentPlayerName);
			}
			writePlayerNames(resp.getWriter() );
			
			respWriter.println("-------------------------<br />");
			respWriter.println("Say: <input type=\"text\" name=\"message\" id=\"idMessage\">");
			respWriter.println("<button type=\"button\" onclick=\"sendMessage('idMessage');\">Send message</button>");
			respWriter.println("<br />Messages: <br />");

			deleteExpiredMessages();
			addToMessages(currentPlayerName, currentPlayerMessage);
			writePlayerMessages(respWriter);
		}
		else
		{
			respWriter.println("</head><body>You must choose a name in order to play.");
		}

		respWriter.println("</body></html>");
	}
	
	protected boolean playerNameExists(String currentPlayerName)
	{
		Query q = new Query(playerNamesKey);
		PreparedQuery pq = datastore.prepare(q);
		
		for (Entity playerEntity: pq.asIterable() )
		{
			String playerName=(String)playerEntity.getProperty(ENTITY_PROPERTY_NAME);
			if (playerName.equalsIgnoreCase(currentPlayerName) )
			{
				return true;
			}
		}
		
		return false;
	}
	
	protected void addPlayerName(String currentPlayerName)
	{
		Entity playerEntityToBeAdded = new Entity(playerNamesKey.getKind(), playerNamesKey);
		playerEntityToBeAdded.setProperty(ENTITY_PROPERTY_NAME, currentPlayerName);
		playerEntityToBeAdded.setProperty(ENTITY_PROPERTY_CREATION_TIME, Long.toString(System.currentTimeMillis() ) );
		datastore.put(playerEntityToBeAdded);
	}
	
	protected void writePlayerNames(PrintWriter respWriter)
			throws IOException
	{
		Query q = new Query(playerNamesKey);
		PreparedQuery pq = datastore.prepare(q);
		
		for (Entity playerEntity: pq.asIterable() )
		{
			respWriter.println( (String)playerEntity.getProperty(ENTITY_PROPERTY_NAME) + "<br />");
		}
	}
	
	protected void deleteExpiredNames()
	{
		Query q = new Query(playerNamesKey);
		PreparedQuery pq = datastore.prepare(q);
		
		for (Entity playerEntity: pq.asIterable() )
		{
			String strPlayerCreationTime = (String)playerEntity.getProperty(ENTITY_PROPERTY_CREATION_TIME);
			long auxPlayerCreationTime = -1;
			if (strPlayerCreationTime != null)
			{
				auxPlayerCreationTime = Long.parseLong(strPlayerCreationTime);
			}
			if ( (System.currentTimeMillis() - auxPlayerCreationTime) / 1000 > LIFETIME_PLAYERNAME)
			{
				datastore.delete(playerEntity.getKey() );
			}
		}
	}
	
	protected void addToMessages(String currentPlayerName, String currentPlayerMessage)
	{
		if (currentPlayerMessage != null)
		{
			Entity messageEntityToBeAdded = new Entity(messagesKey.getKind(), messagesKey);
			messageEntityToBeAdded.setProperty(ENTITY_PROPERTY_NAME, currentPlayerName);
			messageEntityToBeAdded.setProperty(ENTITY_PROPERTY_MESSAGE, currentPlayerMessage);
			messageEntityToBeAdded.setProperty(ENTITY_PROPERTY_CREATION_TIME, Long.toString(System.currentTimeMillis() ) );
			datastore.put(messageEntityToBeAdded);
		}
	}
	
	protected void writePlayerMessages(PrintWriter respWriter)
			throws IOException
	{	
		Query q = new Query(messagesKey);
		PreparedQuery pq = datastore.prepare(q);
		
		for (Entity messageEntity: pq.asIterable() )
		{
			String auxPlayerNameForMessage = (String)messageEntity.getProperty(ENTITY_PROPERTY_NAME);
			String auxMessage = (String)messageEntity.getProperty(ENTITY_PROPERTY_MESSAGE);
			respWriter.println(auxPlayerNameForMessage + ": " + auxMessage + "<br />");
		}
	}
	
	protected void deleteExpiredMessages()
	{
		Query q = new Query(messagesKey);
		PreparedQuery pq = datastore.prepare(q);
		
		for (Entity messageEntity: pq.asIterable() )
		{
			String strMessageCreationTime = (String)messageEntity.getProperty(ENTITY_PROPERTY_CREATION_TIME);
			long auxMessageCreationTime = -1;
			if (strMessageCreationTime != null)
			{
				auxMessageCreationTime = Long.parseLong(strMessageCreationTime);
				if ( (System.currentTimeMillis() - auxMessageCreationTime) / 1000 > LIFETIME_PLAYERMESSAGE)
				{
					datastore.delete(messageEntity.getKey() );
				}
			}
		}
	}
	
	protected String escapeHTML(String strToEscape)
	{
		if (strToEscape != null)
		{
			return strToEscape.replace("<", "&lt;").replace(">", "&gt;");
		}
		
		return strToEscape;
	}
}
